/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.openbookformat.page;


import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.text.BadLocationException;
import org.openbookformat.obffinder.FindResult;
import org.openbookformat.tags.FnMarkTag;
import org.openbookformat.tags.FootnoteTag;
import org.openbookformat.tags.PagebreakTag;
import org.openbookformat.tags.TagParsingException;
import org.openide.cookies.EditorCookie;
import org.openide.util.Exceptions;

/**
 *
 * @author matamh0a
 */
public class PagesManager implements PropertyChangeListener {

    ArrayList<Page> pages;
    EditorCookie ed;
    int firstPage = -1;
    int pageCount = 0;

    public PagesManager(EditorCookie ed) throws TagParsingException {
        this.ed = ed;
        pages = new ArrayList<Page>();
        parsePages();
    }

    private void parsePages() throws TagParsingException {
        String text = null;
        try {
            text = ed.openDocument().getText(0, ed.getDocument().getLength());
        } catch (BadLocationException ex) {
            Exceptions.printStackTrace(ex);
        } catch (IOException ex) {
                Exceptions.printStackTrace(ex);
        }
        
        Pattern pattern = Pattern.compile("<book-part\\sindex=.*?>");
        Matcher matcher = pattern.matcher(text);
        Page page = null;
        if (!matcher.find()) {
            return;
        }
        int offset = matcher.start() + matcher.group().length();
        int length = -1;

        pattern = Pattern.compile(PagebreakTag.TAG_PATTERN);
        matcher = pattern.matcher(text);
        while (matcher.find()) {
            matcher.group();
            if (firstPage == -1) {
                firstPage = PagebreakTag.parse(
                        matcher.group()).getPageNumber();
            }
            length = matcher.start() - offset;
            page = new Page(ed, offset, length,
                    firstPage == -1 ? -1 : firstPage + ++pageCount);
            pages.add(page);
            page.addPropertyChangeListener(this);
            offset = matcher.end();
//                System.out.println("-------------------------------------");
//                page = pages.get(pages.size() -1);
//                System.out.println("offset:" + page.offset);
//                System.out.println("length:" + page.length);
//                System.out.println("Footnote?" + page.hasFootnote());                
//                System.out.println("Body Length:" + page.getBody().length());
        }
    }

    public Page getPage(int pageNum) {
        pageNum -= firstPage + 1;
        return pages.get(pageNum);
    }

    public int getFirstPageNumber() {
        if (!pages.isEmpty()) {
            return pages.get(0).getPageNumber();
        }
        return -1;
    }

    public int getLastPageNumber() {
        if (!pages.isEmpty()) {
            return pages.get(pages.size() - 1).getPageNumber();
        }
        return -1;
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        int pageNumber = ((Page) evt.getSource()).getPageNumber();
        int diff = ((Integer) evt.getNewValue()).intValue()
                - ((Integer) evt.getOldValue()).intValue();
        int lastPage = getLastPageNumber();
        for (int i = pageNumber + 1; i <= lastPage; i++) {
            getPage(i).updateOffset(diff);
        }

    }
    
     /**
     * 
     * @param n page number
     */
    public ArrayList<FindResult> associateFootnotes(
            int n) {
        
        ArrayList<FindResult> r = new ArrayList<FindResult>();
        
        Page page = getPage(n);
        //if the page does not have footnote; we're done.
        if(!page.hasFootnote())
            return r;
        
        //TODO: parse options
        String message = 
                "-p         [start_page:end_page,apage]        #comma seperated pages, use ':' for range\t\n" +
                "-t         pattern\t\t#footnotemark pattern";
        String markPattern = "\\Q(\\E@@mark@@\\Q)\\E";
        String defMsg = "-t " + markPattern;
        //String options = JOptionPane.showInputDialog(message, defMsg);
        
        String body = page.getBody();
        String mark = null;
        FootnoteTag fnTag = page.getFootnote();
        Pattern pattern = null;
        Matcher matcher = null;
        ArrayList<Bookmark> marks = new ArrayList<Bookmark>();
        int count = -1;
        for(int i = 0; i < fnTag.size(); i++) {
            mark = fnTag.getFnTextTag(i).getMark();
            
            //check if the mark is already exist.
            if(body.contains((new FnMarkTag(mark)).toString()))
                continue;
                       
            //search for mark
            marks.clear();
            pattern = Pattern.compile(markPattern.replace("@@mark@@", mark));
            matcher = pattern.matcher(body);
            //System.out.println("Pattern:" + markPattern.replace("@@mark@@", mark));
            while(matcher.find()) {
                matcher.group();
                marks.add(new Bookmark(matcher.start(), 
                        matcher.end() - matcher.start()));
                //System.out.println(marks.get(marks.size() -1));
            }
            
            if(marks.size() == 1) {
                //perfect match
                r.add(new FindResult(ed,
                        page.getOffset() + marks.get(0).getOffset(),
                        true, body.substring(marks.get(0).getOffset(),
                        marks.get(0).getOffset() + marks.get(0).getLength()),
                        (new FnMarkTag(mark)).toString()));
            } else {
                //we have a problem
                PageFootnoteDialog dialog = new PageFootnoteDialog(null, true);
                dialog.setPage(page);
                dialog.setMarks(marks);
                dialog.setFnText(fnTag.getFnTextTag(i));
                dialog.setLtr(false);
                //dialog.setEditMode(marks.isEmpty());
                dialog.init();
                dialog.setVisible(true);
                if(dialog.isPageModified()) {
                    return associateFootnotes(n);
                }
                
                if(dialog.getSelection() == PageFootnoteDialog.OK_OPTOIN) {
                    Bookmark aMark = null;
                    for(int l = 0; l < dialog.getMarks().size(); l++) {
                        aMark = dialog.getMarks().get(l);
                        if(aMark.isSelected()) {
                            r.add(new FindResult(ed,
                                    page.getOffset() + aMark.getOffset(),
                                    true, body.substring(aMark.getOffset(),
                                    aMark.getOffset() + aMark.getLength()),
                                    (new FnMarkTag(mark)).toString()));
                        }
                    }
                }
            }
        }        
        return r;
    }

}
